import java.io.*;
import java.net.*;
import java.util.*;


public class Server {
	public static GameState game;
	public static Communication c;
	public static final String welcome = "Hello, and welcome to Kevin's agrimoo server!";
	public static void main(String args[]) throws IOException{
		game = new GameState();
		c = new Communication(1337);
		new Thread(c).start();
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		String command = "";
		System.out.print("> ");
		while(true) {
			command = in.readLine();
			if(command.equals("resetchat")) {
				game.chat.messages.clear();
			} else if (command.equals("listclients")) {
				System.out.println(Communication.clients);
			} else if(command.equals("quit") || command.equals("exit")) {
				System.exit(0);
			}
			System.out.print("> ");
		}
		//game.startround();
	}
	public static void handle(Message m) {
		switch(m.type) {
		case Message.CHAT:
			System.out.println("Got chat message: "+m.text+" from "+m.from);
			game.chat.messages.add(game.chat.new Message("<b>" + m.from + ":</b> " + m.text,null));
			break;
		case Message.DISPLAY:
			System.out.println(m.text);
			break;
		case Message.ACTION:
			System.out.println("Player " + m.from + " performed action " + game.board.actioncards.get(m.number).name);
			game.board.actioncards.get(m.number).action(m.from.p);
			break;
		}
		updateall();
	}
	private static void updateall() {
		for(Communication.Client k : Communication.clients) {
			k.sendMessage(new Message(Message.UPDATE, game));
		}
	}
	public static class Communication implements Runnable {
		public static ServerSocket socket;
		public static ArrayList<Client> clients = new ArrayList<Client>();
		public Communication(int s) {
			try {
				socket = new ServerSocket(s);
				socket.setSoTimeout(10);
			} catch (IOException e) {
				e.printStackTrace();
				System.out.println("Failed somehow to create communication class");
			}
		}
		public void run() {
			Socket s = null;
			Message m = null;
			int deadtimer = 0;
			ArrayList<Client> deadclients = new ArrayList<Client>();
			while(true) {
				try {
					s = socket.accept();
				} catch (IOException e) {
					//continue;
				}
				if(s != null) {
					System.out.println("Got connection "+s.toString());
					Player p = new Player();
					clients.add(new Client(s, p));
					game.players.add(p);
					s = null;
				}
				for(Client c : clients) {
					if(deadtimer > 1000 && !c.sendMessage(new Message(-1,"test"))) {
						deadclients.add(c);
					}
					try {
						if(c.b.available() > 1) {
							m = (Message)c.objin.readObject();
						}
					} catch (IOException e) {
					} catch (ClassNotFoundException e) {
					}
					if(m != null) {
						m.from = c;
						Server.handle(m);
						m = null;
					}
				}
				if(deadtimer > 1000) {
					deadtimer = 0;
				} else {
					deadtimer++;
				}
				if(!deadclients.isEmpty()) {
					System.out.println("Killed some bitches " + deadclients.toString());
					clients.removeAll(deadclients);
					deadclients.clear();
				}
			}
		}
		
		public static class Client {
			public Socket s;
			public ObjectInputStream objin;
			public BufferedInputStream b;
			public ObjectOutputStream objout;
			public Player p;
			public Client(Socket sock, Player ply) {
				p = ply;
				game.players.add(p);
				s = sock;
				try {
					objout = new ObjectOutputStream(s.getOutputStream());
					b = new BufferedInputStream(s.getInputStream());
					objin = new ObjectInputStream(b);
					objout.writeObject(game);
					sendMessage(new Message(Message.PLAYER, game.players.indexOf(p)));
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendAlert(welcome);
			}
			public boolean sendMessage(Message m) {
				try {
					objout.writeObject(m);
					objout.reset();
				} catch (IOException e) {
					return false;
				}
				return true;
			}
			public void sendAlert(String s) {
				Message m = new Message(Message.DISPLAY, s);
				sendMessage(m);
			}
			public String toString() {
				return s.getInetAddress().toString();
			}
		}
	}
}
